package com.powergisol.core.model;


import com.powergisol.core.math.Dot;
import com.powergisol.core.math.Line;
import com.powergisol.core.math.Plane;
import com.powergisol.core.processer.SectionProcesser;
import com.powergisol.exception.GeoBuildException;
import com.powergisol.gis.geom.GeoLineString;
import com.powergisol.gis.geom.GeoPoint;
import com.powergisol.gis.geom.GeoPolygon;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Polygon;

import java.util.ArrayList;
import java.util.List;

/**
 * 切面生成器
 */
public class SectionCreater {


    SectionProcesser delegate;

    public SectionCreater() {

        delegate = new SectionProcesser() {
            @Override
            public List<GeoPolygon> createSection(GeoPolygon section, List<GeoPolygon> polygons) {

                List<GeoPolygon> geoPolygons = new ArrayList<>();

                for (int i = 0; i < polygons.size() - 1; i++) {

                    List<Dot> dots = new ArrayList<>();

                    GeoPolygon polygonUp = polygons.get(i);
                    GeoPolygon polygonDown = polygons.get(i + 1);

                    List<Dot> dotsUp = getIntersectPoint(section, polygonUp);
                    if (!dotsUp.isEmpty()) {
                        dots.addAll(dotsUp);
                        List<Dot> dotsDown = getIntersectPoint(section, polygonDown);
                        dots.addAll(dotsDown);
                    }
                    /**
                     * 构建4边形
                     */
                    GeoPolygon geoPolygon = new GeoPolygon(dots);
                    geoPolygons.add(geoPolygon);
                }

                return geoPolygons;
            }

            /**
             *
             * @param section
             * @param polygon
             * @param height
             * @return
             */
            public List<Dot> getIntersectPoint(GeoPolygon section, GeoPolygon polygon,double height){
                Plane sectionPlane = section.toPlane();
                Plane plane = polygon.toPlane();

                List<Line> lines = plane.getLines();

                List<Dot> dots = new ArrayList<>();

                lines.forEach(line -> {
                    /**
                     * 求面与线的交点
                     */
                    Dot intersection = sectionPlane.getIntersection(line);
                    if (line.contains(intersection)) {
                        dots.add(intersection);
                    }

                });

                if (dots.size() == 2) {
                    System.out.println("binggo!");
                }

                return dots;
            }

            /**
             *
             * @param section
             * @param polygon
             * @return
             */
            public List<Dot> getIntersectPoint(GeoPolygon section, GeoPolygon polygon) {

                Plane sectionPlane = section.toPlane();
                Plane plane = polygon.toPlane();

                List<Line> lines = plane.getLines();

                List<Dot> dots = new ArrayList<>();

                lines.forEach(line -> {
                    /**
                     * 求面与线的交点
                     */
                    Dot intersection = sectionPlane.getIntersection(line);
                    if (line.contains(intersection)) {
                        dots.add(intersection);
                    }

                });
                /**
                 * 如果只有1个交点,另一个交点在切面的4条边上
                 */
                if (dots.size() == 1) {
                    //切面为4条边
                    List<Line> sectionLines = sectionPlane.getLines();

                    sectionLines.forEach(line -> {

                        Dot intersection = plane.getIntersection(line);

                        if (line.contains(intersection)) {
                            dots.add(intersection);
                        }
                    });
                }

                if (dots.size() == 2) {
                    System.out.println("binggo!");
                }

                return dots;
            }

            private double getMaxZ(GeoLineString lineString,double height){


                Coordinate[] coordinates = lineString.getCoordinates();
                double z = coordinates[0].z;
                return z - height;
            }

            /**
             * 判断线和面是否投影相交,满足这个条件才往后进行
             * @param lineString
             * @param polygon
             * @param height
             * @return
             */
            @Override
            public List<Dot> getIntersectPoint(GeoLineString lineString, GeoPolygon polygon, double height) {

                GeoPolygon geoPolygon = buildSection(lineString, height);
                Plane sectionPlane = geoPolygon.toPlane();
                Plane plane = polygon.toPlane();

                List<Line> lines = plane.getLines();
                List<Dot> dots = new ArrayList<>();
                LineString string = lineString.toGeometry();
                /**
                 * 投影线
                 */
                Line oldLine = lineString.toLine();
                Dot dotM = new Dot(oldLine.getM().getX(),oldLine.getM().getY(),0);
                Dot dotN = new Dot(oldLine.getN().getX(),oldLine.getN().getY(),0);
                Line newLine = new Line(dotM,dotN);
                /**
                 * 投影三角面
                 */
                Polygon geometry = polygon.toGeometry();
                /**
                 * 二者必须投影相交我们才认为切面是切到三角形的
                 */

                if(string.intersects(geometry)){
                    lines.forEach(line -> {
                        /**
                         * 求面与线的交点
                         */
                        Dot intersection = sectionPlane.getIntersection(line);
                        /**
                         * 投影点
                         */
                        Dot point = new Dot(intersection.getX(),intersection.getY(),0);

                        if (line.contains(intersection)) {
                            if(newLine.contains(point)){
                                dots.add(intersection);
                            }

                        }

                    });
                    /**
                     * 如果只有1个交点,另一个交点在切面的4条边上
                     */
                    if (dots.size() == 1) {
                        //切面为4条边
                        List<Line> sectionLines = sectionPlane.getLines();

                        sectionLines.forEach(line -> {

                            Dot intersection = plane.getIntersection(line);

                            /**
                             * 投影点
                             */
                            GeoPoint point = new GeoPoint(intersection.getX(),intersection.getY());


                            if (line.contains(intersection)) {
                                if(polygon.toGeometry().contains(point.toGeometry())){
                                    dots.add(intersection);
                                }

                            }
                        });
                    }

                    if (dots.size() == 2) {
                        System.out.println("binggo!");
                    }
                }
                return dots;
            }


            /**
             * 根据前端位绘制的线加深度来算面
             *
             * @param strings
             * @param height
             * @return
             */
            private GeoPolygon buildSection(GeoLineString strings, double height) {


                Coordinate[] coordinates = strings.getCoordinates();

                if (coordinates.length != 2) {
                    throw new GeoBuildException("直线有且只有两个点");
                }

                Coordinate coordinate0 = coordinates[0];
                Coordinate coordinate1 = coordinates[1];
                //构建第三第四个顶点
                Coordinate coordinate2 = new Coordinate(coordinate1.x, coordinate1.y, coordinate1.z - height);
                Coordinate coordinate3 = new Coordinate(coordinate0.x, coordinate0.y, coordinate0.z - height);

                //构建切面
                GeoPolygon polygon = new GeoPolygon(new Coordinate[]{coordinate0, coordinate1, coordinate2, coordinate3, coordinate0});


                return polygon;
            }


        };
    }

    /**
     * 虽然这里求到的是面和直线的相交点,但是我们的面是有范围的面,我们这里的解决方法是:因为是切面.然后采取投影的方式,把绘制的线投影到Z=0的面上,然后
     * 如果交点在线段上,不是线的延长线上.就说明这个是符合要求的点
     */

    public List<Dot> getIntersectPoint(GeoLineString lineString, GeoPolygon polygon, double height) {
        return delegate.getIntersectPoint(lineString, polygon, height);
    }

    public void setDelegate(SectionProcesser delegate) {
        this.delegate = delegate;
    }

    /**
     * 切面与其它面的交点,模型的每个层有上下两个面,两个面都为三角形,且顶点的X Y坐标都相同,
     * 最终的问题是转换成三角形三条边与面的相交关系,求得上下
     *
     * @param section
     * @param polygons
     * @return
     */
    public List<GeoPolygon> createSection(GeoPolygon section, List<GeoPolygon> polygons) {

        return delegate.createSection(section, polygons);

    }

    /**
     *
     * @param section
     * @param polygon
     * @param height
     * @return
     */
    public List<Dot> getIntersectPoint(GeoPolygon section, GeoPolygon polygon,double height){
        return delegate.getIntersectPoint(section,polygon,height);
    }


    /**
     * 获取面和面的交点
     *
     * @param section
     * @param polygon
     * @return
     */
    public List<Dot> getIntersectPoint(GeoPolygon section, GeoPolygon polygon) {
        return delegate.getIntersectPoint(section, polygon);
    }

    public static void main(String[] args) {
        SectionCreater creater = new SectionCreater();
        GeoLineString string = new GeoLineString(113.22743328694796,23.187016287595235,16.743524958339485,113.22761188636142, 23.186882912244972, 17.281934417376775);
        List<Dot> dots = new ArrayList<>();

        Dot dot1 = new Dot(113.227623 ,23.1869,6.11789113);
        Dot dot2 = new Dot(113.2276 ,23.1868782,5.89936543);
        Dot dot3 = new Dot(113.227646 ,23.186861,6.089134);
        dots.add(dot1);
        dots.add(dot2);
        dots.add(dot3);
        dots.add(dot1);
        GeoPolygon geoPolygon = new GeoPolygon(dots);
        List<Dot> intersectPoint = creater.getIntersectPoint(string, geoPolygon, 1000);

        System.out.println();
    }

}
